package com.cskaoyan.javase._1extends._9override;

/**
 * 首先，这一章节的名字叫做：“方法的覆盖”
 * 但实际上我们主要探究"对象名.成员方法名"的调用机制。
 * 只要创建子类对象，调用父子类的test方法，调用的结果都是子类中同名方法的执行结果。
 * 当然，方法不过是方法区的二进制指令合集罢了，类加载时期，装载进方法区，肯定不会物理消失。
 * 只不过是因为"对象名.成员方法名"的调用机制,体现为方法的覆盖
 * 接下来我们就来探讨一下这种对象名点访问成员方法的机制。
 *
 * 和前面访问成员变量一样，在研究 对象名点访问成员方法 机制时，我们主要探究两个方向：
 *      1.访问范围，究竟能够访问到哪些成员方法？根据什么来决定？
 *      2.访问结果，如果是父子类同名成员方法，那么结果是什么？根据什么来决定？
 *
 *
 * 首先是 对象名点访问成员方法 ，对象的由来，可以有三种方式：
 *      1.创建父类对象,用父类引用接收，用对象名点访问。
 *      2.创建子类对象,用子类引用接收，用对象名点访问。
 *      3.创建子类对象,用父类引用接收，用对象名点访问。
 *
 *
 *  1.首先访问范围仍然是编译上的概念,和对象名.成员变量是一样的机制,都仅由引用的数据类型来决定
 *
 *  2.重点研究方法调用的结果:
 *       1.创建父类对象,用父类引用接收，用对象名点访问。
 *       结果肯定是父类中的行为
 *
 *      2.创建子类对象,用子类引用接收，用对象名点访问。
 *      结果肯定是子类中的行为
 *
 *      3.(重点)创建子类对象,用父类引用接收，用对象名点访问。
 *      结果是子类中的行为
 *
 * 以上,"对象名.成员方法"的调用结果是根据对象的具体类型来决定的
 * 也就是说,"对象名.成员方法"访问范围是编译器决定的,是编译时期就能够确定的
 * 而调用的结果必须等待程序运行,根据对象的具体类型,来决定具体的执行结果.
 *
 *
 * @since 10:51
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*Son s = new Son();
        s.test();
        s.invokeFatherTest();
        s.superInvokeFatherTest();*/

        // 1.创建父类对象,用父类引用接收，用对象名点访问。
        Father f = new Father();
        f.test();
        f.fatherTest();

        // 2.创建子类对象,用子类引用接收，用对象名点访问。
        Son s = new Son();
        s.sonTest();
        s.fatherTest();
        s.test();

        // 3.创建子类对象,用父类引用接收，用对象名点访问。
        Father fs = new Son();
        fs.test();
        // fs.fatherTest();
        // ((Son) fs).sonTest();
    }
}

class Father {
    public void test() {
        System.out.println("father");
    }

    /*public void invokeFatherTest() {
        test();
    }*/
    public void fatherTest() {
        System.out.println("only father");
    }
}

class Son extends Father {
    public void test() {
        System.out.println("son");
    }

    public void sonTest() {
        System.out.println("only son");
    }

    /*public void superInvokeFatherTest() {
        super.test();
    }*/
}